package com.hunter.lucene.util.search;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import org.apache.lucene.search.Filter;
import org.apache.lucene.search.Query;

import com.hunter.lucene.util.search.build.ObjectBuildException;
import com.hunter.lucene.util.search.build.ObjectsBuilder;
import com.hunter.lucene.util.search.query.AllScoreSortedCollector;

/**
 * 
 * @author bastengao
 * 
 */
public class AllScoreSortedQuerySession implements QuerySession {
	private Query query = null;// 查询
	private Filter filter = null;// 过滤
	private SearchWorker worker = null;//
	private AllScoreSortedCollector collector = null;
	private Queue<Object> userDatas = new LinkedList<Object>();
	private ObjectsBuilder objectsBuilder = null;

	public AllScoreSortedQuerySession(Query query, SearchWorker worker,
			ObjectsBuilder objectsBuilder) {
		super();
		this.query = query;
		this.worker = worker;
		this.objectsBuilder = objectsBuilder;
	}

	public AllScoreSortedQuerySession(Query query, Filter filter,
			SearchWorker worker, ObjectsBuilder objectsBuilder) {
		super();
		this.query = query;
		this.filter = filter;
		this.worker = worker;
		this.objectsBuilder = objectsBuilder;
	}

	@Override
	public void close() {
		collector = null;
		userDatas = null;
		objectsBuilder = null;
	}

	@Override
	public void execute() throws SearchException {
		collector = new AllScoreSortedCollector();
		if (filter == null) {
			try {
				worker.excuteQuery(query, collector);
			} catch (IOException e) {
				e.printStackTrace();
				throw new SearchException(e);
			}
		} else {
			try {
				worker.excuteQuery(query, filter, collector);
			} catch (IOException e) {
				e.printStackTrace();
				throw new SearchException(e);
			}
		}
		tryEnsureHasOne();
	}

	@Override
	public boolean hasMore() {

		return userDatas.size() > 0;
	}

	@Override
	public Object next() throws SearchException {
		Object userData = userDatas.poll();
		tryEnsureHasOne();
		return userData;
	}

	@Override
	public List<Object> next(int length) throws SearchException {
		tryEnsureHasMore(length);
		List<Object> datas = new ArrayList<Object>(length);
		while (datas.size() < length && userDatas.size() > 0) {
			datas.add(userDatas.poll());
		}
		tryEnsureHasOne();
		return datas;
	}

	/**
	 * 执行此方法，来尽力去保证还有 一个 UserData
	 * 
	 * @throws SearchException
	 */
	private void tryEnsureHasOne() throws SearchException {
		tryEnsureHasMore(1);
	}

	/**
	 * 执行此方法，来尽力去保证至少还有 n 个 UserData,但不保证一定有 n 个 UserData
	 * 
	 * @param size
	 * @throws SearchException
	 */
	private void tryEnsureHasMore(int size) throws SearchException {
		while (userDatas.size() < size && collector.size() > 0) {

			// if get document by id that not exists ,which will throw this
			// IOException
			// and this method maybe get a document that is deleted
			// already,lucene recommends to verify use isDeleted(id)

			int docId = collector.poll().doc;

			Object userData = null;
			try {
				userData = objectsBuilder.build(docId);
			} catch (ObjectBuildException e) {
				e.printStackTrace();
				throw new SearchException(e);
			}
			if (userData != null) {
				userDatas.add(userData);
			}

		}
	}

}
